<template>
  <div class="cardItemX" :class="{isChildren: isLastLevel}">
    <!-- 当前是最后一层 -->
    <span class="checkBox lastLevel" v-if="isLastLevel">
      <el-checkbox v-model="nowItem[propsD.checkX]" :disabled="nowItem[propsD.disabled]"
                   @change="changeFn(nowItem,$event)">
        <span class="slotBox">
          <slot name="icon" :data="nowItem">
            <icon-x :type="nowItem[propsD.icon]"/>
          </slot>
          <slot name="title" :data="nowItem">
            <span class="menuTitle">{{ nowItem[propsD.title] }}</span>
          </slot>
        </span>
      </el-checkbox>
    </span>

    <!-- 不是最后一层 -->
    <div class="noLastLevel cardBox" v-else :class="{child: !isFirstLevel}">
      <el-card class="groupItem" :id="nowItem[propsD.key]" shadow="hover">

        <!-- 父级的样式 -->
        <div class="fatherTitle checkBox">
          <el-checkbox v-model="nowItem[propsD.checkX]" border
                       :disabled="nowItem[propsD.disabledX]"
                       @change="changeFn(nowItem,$event)" :indeterminate="nowItem[propsD.awaitX]">
            <span class="slotBox">
              <slot name="icon" :data="nowItem">
                <icon-x :type="nowItem[propsD.icon]"/>
              </slot>
              <slot name="title" :data="nowItem">
                <span class="menuTitle">{{ nowItem[propsD.title] }}</span>
              </slot>
            </span>
          </el-checkbox>
        </div>

        <!-- 判断该层是否包含子级 -->
        <span class="haveChildren child" v-for="item in nowItem[propsD.children]" :key="item[propsD.key]">
          <card-item-x :props="propsD" :list="props.list"
                       :margin-left="marginLeftD" @check="checkFn"
                       :item="item" :change="props.change">
              <template #title="{data}">
                <slot name="title" :data="data"/>
              </template>

              <template #icon="{data}">
                <slot name="icon" :data="data"/>
              </template>
          </card-item-x>
        </span>

      </el-card>
    </div>


  </div>
</template>

<script setup>
import {ref, watch, computed} from 'vue'
import IconX from "../xhykIcon.vue";
import CardItemX from './xhykCardMenuItem.vue'
import { ElCheckbox,ElCard } from 'element-plus'

const props = defineProps({
  // 配置
  props: {
    type: Object,
    default: {
      key: 'name',
      icon: 'icon',
      children: 'children',
      title: 'title',
      // 禁止
      disabledX: 'disabledX',
      // 勾选字段
      checkX: 'checkX',
      // 待定字段
      awaitX: 'awaitX'
    }
  },

  // 当前数据
  item: {
    type: Object,
    default: {}
  },

  // 菜单列表
  list: {
    type: Object,
    default: []
  },

  // 勾选事件。返回false时则取消勾选下层的操作
  change: {
    type: Function,
    default: async (item, toCheck) => {

    }
  },

  // 左边缩进
  marginLeft: {
    type: [String, Number],
    default: "24px"
  },

})

const emit = defineEmits(['check'])

// 配置信息
const propsD = computed(() => {
  let result = {
    key: props.props.name || 'name',
    icon: props.props.icon || 'icon',
    children: props.props.children || 'children',
    title: props.props.title || 'title',
    // 禁止
    disabledX: props.props.disabledX || 'disabledX',
    // 勾选字段
    checkX: props.props.checkX || 'checkX',
    // 待定字段
    awaitX: props.props.awaitX || 'awaitX'
  }
  return result
})

// 左边缩进
const marginLeftD = computed(() => {
  let result = "24px"
  let thisValue = props.marginLeft
  if (typeof thisValue == 'string') {
    result = thisValue
    if (!result.includes('%') && !result.includes("rpx") &&
        !result.includes("vw") && !result.includes("vh") &&
        !result.includes("auto") && !result.includes("em") && !result.includes("px")) {
      result = `${result}px`
    }
  } else if (typeof thisValue == 'number') {
    result = `${thisValue}px`
  }
  return result
})

// 当前父级
const nowItem = ref({})

// 当前数据是否为最后一层的子菜单
const isLastLevel = ref(false)

// 当前数据是否为第一层菜单
const isFirstLevel = ref(true)

/* 函数 */
// 判断是否最后一层
const isLastFn = (row) => {
  const tempList = row[propsD.value.children] || []
  return tempList.length <= 0
}


// 遍历嵌套取对象。根据children字段遍历下级列表。返回当前子级对象
async function findChildren(data = [], callBack = undefined, children = "children") {
  let tempResult = undefined
  const findFn = async (ChildData, father) => {
    let isOk = false
    for (let item of ChildData) {
      if (typeof callBack == "function") {
        const isBreak = await callBack(item, father)
        if (isBreak == true) {
          tempResult = item
          isOk = true
          break;
        }
      }
      if (isOk) {
        tempResult = item
        return item
      }

      // 如果有下一级数据
      if (item[children] != undefined && item[children].length > 0) {
        let result = await findFn(item[children], item)
        if (result) {
          return true
        }
      }
    }
    return isOk;
  }
  await findFn(data, {})
  return tempResult
}


// 当前勾选事件
const changeFn = async (item, toCheck, event = true) => {
  // 是否发送事件
  if (event) {
    emit("check", {
      item: item,
      toCheck: toCheck
    })
  }
  item[propsD.value.checkX] = toCheck
  let result = await props.change(item, toCheck);
  // 是否需要默认事件
  if (result != false) {
    toChangeFn(item, toCheck)
  }else{
    item[propsD.value.checkX] = !toCheck
  }
}

// 子级勾选事件
const checkFn = ({item, toCheck}) => {
  emit("check", {
    item: item,
    toCheck: toCheck
  })
}

// 组件内部默认的事件
const toChangeFn = (item, toChoose) => {
  if (toChoose) {
    item[propsD.value.awaitX] = false
  }
  if (!isLastFn(item)) {
    changeChild(item, toChoose)
  }
  changeFather(item)
}


// 勾选父级，全部子级勾选
const changeChild = (father, choose) => {
  const list = father[propsD.value.children] || []
  list.forEach(item => {
    item[propsD.value.checkX] = choose
    if (!isLastFn(item)) {
      changeChild(item, choose)
    }
  })
  changeFather(father)
}


// 勾选父级
const changeFather = async (item) => {
  // 判断被改变的对象是否有父级。是子级则代表有父级
  // 获取这个子级的父级
  let thisFather = undefined
  await findChildren(props.list, (row, father) => {
    if (item[propsD.value.key] == row[propsD.value.key]) {
      thisFather = father
      return true;
    }
  })
  if (thisFather == undefined) {
    return;
  }
  // 先待定状态改为false
  thisFather[propsD.value.awaitX] = false
  // 判断是否全部子级都选上
  let checkList = [] // 子级中已经勾选的
  let isIndeterminate = [] // 子级中存在待定的
  const childList = thisFather[propsD.value.children] || []
  childList.forEach(row => {
    row[propsD.value.checkX] == true ? checkList.push(row) : undefined
    row[propsD.value.awaitX] == true ? isIndeterminate.push(row) : undefined
  })
  // 开始判断状态
  // console.log(isIndeterminate)
  if (checkList.length == childList.length) {
    // 全部勾选
    thisFather[propsD.value.checkX] = true
  } else if (checkList.length <= 0) {
    // 一个都没有选中
    thisFather[propsD.value.checkX] = false
    // 判断子级是否存在待定的
    if (isIndeterminate.length > 0) {
      thisFather[propsD.value.awaitX] = true
    }
  } else {
    // 选了其中一些子级
    thisFather[propsD.value.checkX] = false
    thisFather[propsD.value.awaitX] = true
  }
  // 再去改变他的父级
  changeFather(thisFather)
}


watch(() => props.item, newV => {
  nowItem.value = newV
  isLastLevel.value = isLastFn(newV)
  const have = props.list.find(row => row[propsD.value.key] == newV[propsD.value.key])
  isFirstLevel.value = have ? true : false;
}, {immediate: true, deep: true})

defineExpose({
  toCheckFn: changeFn
})
</script>

<style scoped lang='scss'>

.isChildren {
  display: inline-block;
}

.cardBox, .checkBox {
  margin-bottom: 10px;
}

.checkBox {
  margin-right: 20px;
}

.child {
  margin-left: v-bind(marginLeftD);
}

// 第一层
.isFirst {
  margin-left: 0px;
}

// 插槽
:deep(.slotBox) {
  display: inline-flex;
  align-items: center;

  .menuTitle {
    margin-left: 2px;
  }
}

</style>